#!/bin/bash

# Debian 11 SSH/SSL更新脚本
# 功能：更新镜像源、编译安装最新OpenSSL和OpenSSH、配置SSH服务
# 作者：System Administrator
# 日期：$(date +%Y-%m-%d)

set -e  # 遇到错误立即退出

# 设置locale环境变量避免perl警告
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# 日志函数
log_info() {
    echo -e "${GREEN}[INFO]${NC} $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $1"
}

# 检查是否为root用户
check_root() {
    if [[ $EUID -ne 0 ]]; then
        log_error "此脚本需要root权限运行"
        exit 1
    fi
}

# 备份重要配置文件
backup_configs() {
    log_info "备份重要配置文件..."
    
    # 创建备份目录
    BACKUP_DIR="/root/config_backup_$(date +%Y%m%d_%H%M%S)"
    mkdir -p "$BACKUP_DIR"
    
    # 备份配置文件
    cp /etc/apt/sources.list "$BACKUP_DIR/" 2>/dev/null || true
    cp /etc/ssh/sshd_config "$BACKUP_DIR/" 2>/dev/null || true
    
    log_info "配置文件已备份到: $BACKUP_DIR"
}

# 更新APT镜像源
update_apt_sources() {
    log_info "更新APT镜像源为中科大镜像..."
    
    cat > /etc/apt/sources.list << EOF
# 中科大镜像源
deb https://mirrors.ustc.edu.cn/debian bullseye main contrib non-free
deb-src https://mirrors.ustc.edu.cn/debian bullseye main contrib non-free

deb https://mirrors.ustc.edu.cn/debian bullseye-updates main contrib non-free
deb-src https://mirrors.ustc.edu.cn/debian bullseye-updates main contrib non-free

deb https://mirrors.ustc.edu.cn/debian bullseye-backports main contrib non-free
deb-src https://mirrors.ustc.edu.cn/debian bullseye-backports main contrib non-free

deb https://mirrors.ustc.edu.cn/debian-security bullseye-security main contrib non-free
deb-src https://mirrors.ustc.edu.cn/debian-security bullseye-security main contrib non-free
EOF
    
    log_info "更新APT包索引..."
    apt update
}

# 安装编译依赖
install_dependencies() {
    log_info "安装编译依赖包..."
    
    # 修复locale问题
    log_info "配置系统locale..."
    apt install -y locales
    echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen
    locale-gen
    export LANG=en_US.UTF-8
    export LC_ALL=en_US.UTF-8
    
    apt install -y \
        build-essential \
        wget \
        curl \
        zlib1g-dev \
        libssl-dev \
        libpam0g-dev \
        libselinux1-dev \
        libkrb5-dev \
        libwrap0-dev \
        libaudit-dev \
        libedit-dev \
        libldns-dev \
        pkg-config \
        autoconf \
        automake \
        libtool \
        make \
        gcc \
        g++
}

# 获取最新版本号
get_latest_versions() {
    log_info "获取OpenSSL和OpenSSH最新版本信息..."
    
    # 获取OpenSSL最新版本
    OPENSSL_VERSION=$(curl -s https://mirrors.cloud.tencent.com/openssl/source/ | \
        grep -oP 'openssl-[0-9]+\.[0-9]+\.[0-9]+[a-z]?\.tar\.gz' | \
        sort -V | tail -1 | sed 's/openssl-\(.*\)\.tar\.gz/\1/')
    
    if [ -z "$OPENSSL_VERSION" ]; then
        log_warn "无法获取OpenSSL最新版本，使用默认版本 3.1.4"
        OPENSSL_VERSION="3.1.4"
    fi
    
    # 获取OpenSSH最新版本
    OPENSSH_VERSION=$(curl -s https://mirrors.cloud.tencent.com/OpenBSD/OpenSSH/portable/ | \
        grep -oP 'openssh-[0-9]+\.[0-9]+p[0-9]+\.tar\.gz' | \
        sort -V | tail -1 | sed 's/openssh-\(.*\)\.tar\.gz/\1/')
    
    if [ -z "$OPENSSH_VERSION" ]; then
        log_warn "无法获取OpenSSH最新版本，使用默认版本 9.5p1"
        OPENSSH_VERSION="9.5p1"
    fi
    
    log_info "OpenSSL版本: $OPENSSL_VERSION"
    log_info "OpenSSH版本: $OPENSSH_VERSION"
}

# 编译安装OpenSSL
install_openssl() {
    log_info "开始编译安装OpenSSL $OPENSSL_VERSION..."
    
    cd /tmp
    
    # 清理可能存在的旧文件
    rm -rf openssl-* 2>/dev/null || true
    
    # 下载OpenSSL源码
    log_info "下载OpenSSL源码包..."
    wget -O openssl-${OPENSSL_VERSION}.tar.gz \
        "https://mirrors.cloud.tencent.com/openssl/source/openssl-${OPENSSL_VERSION}.tar.gz"
    
    # 验证下载是否成功
    if [ ! -f "openssl-${OPENSSL_VERSION}.tar.gz" ]; then
        log_error "OpenSSL源码包下载失败"
        exit 1
    fi
    
    # 解压并验证
    log_info "解压OpenSSL源码包..."
    tar -xzf openssl-${OPENSSL_VERSION}.tar.gz
    
    # 查找实际的目录名
    OPENSSL_DIR=$(find /tmp -maxdepth 1 -type d -name "openssl-*" | head -1)
    if [ -z "$OPENSSL_DIR" ] || [ ! -d "$OPENSSL_DIR" ]; then
        log_error "OpenSSL源码解压失败或目录不存在"
        ls -la /tmp/openssl* || true
        exit 1
    fi
    
    log_info "进入目录: $OPENSSL_DIR"
    cd "$OPENSSL_DIR"
    
    # 配置编译选项
    log_info "配置编译选项..."
    ./config --prefix=/usr/local/ssl \
             --openssldir=/usr/local/ssl \
             shared \
             zlib
    
    # 编译
    log_info "开始编译OpenSSL..."
    make -j$(nproc)
    
    # 安装
    log_info "安装OpenSSL..."
    make install
    
    # 更新库路径
    echo "/usr/local/ssl/lib" > /etc/ld.so.conf.d/openssl.conf
    echo "/usr/local/ssl/lib64" >> /etc/ld.so.conf.d/openssl.conf
    ldconfig
    
    # 创建软链接
    ln -sf /usr/local/ssl/bin/openssl /usr/bin/openssl
    
    # 更新环境变量
    export LD_LIBRARY_PATH="/usr/local/ssl/lib:/usr/local/ssl/lib64:$LD_LIBRARY_PATH"
    echo 'export LD_LIBRARY_PATH="/usr/local/ssl/lib:/usr/local/ssl/lib64:$LD_LIBRARY_PATH"' >> /etc/environment
    
    # 创建pkg-config文件
    mkdir -p /usr/local/lib/pkgconfig
    cat > /usr/local/lib/pkgconfig/openssl.pc << EOF
prefix=/usr/local/ssl
exec_prefix=\${prefix}
libdir=\${exec_prefix}/lib
includedir=\${prefix}/include

Name: OpenSSL
Description: Secure Sockets Layer toolkit
Version: ${OPENSSL_VERSION}
Requires: 
Libs: -L\${libdir} -lssl -lcrypto
Libs.private: -ldl -pthread
Cflags: -I\${includedir}
EOF
    
    cat > /usr/local/lib/pkgconfig/libssl.pc << EOF
prefix=/usr/local/ssl
exec_prefix=\${prefix}
libdir=\${exec_prefix}/lib
includedir=\${prefix}/include

Name: OpenSSL-libssl
Description: Secure Sockets Layer toolkit - libssl
Version: ${OPENSSL_VERSION}
Requires: libcrypto
Libs: -L\${libdir} -lssl
Cflags: -I\${includedir}
EOF
    
    cat > /usr/local/lib/pkgconfig/libcrypto.pc << EOF
prefix=/usr/local/ssl
exec_prefix=\${prefix}
libdir=\${exec_prefix}/lib
includedir=\${prefix}/include

Name: OpenSSL-libcrypto
Description: OpenSSL cryptography library
Version: ${OPENSSL_VERSION}
Libs: -L\${libdir} -lcrypto
Libs.private: -ldl -pthread
Cflags: -I\${includedir}
EOF
    
    # 更新PKG_CONFIG_PATH
    export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH"
    
    log_info "OpenSSL安装完成"
    # 重新加载环境变量
    source /etc/environment 2>/dev/null || true
    # 显示版本信息
    LD_LIBRARY_PATH="/usr/local/ssl/lib:/usr/local/ssl/lib64:$LD_LIBRARY_PATH" openssl version
}

# 编译安装OpenSSH
install_openssh() {
    log_info "开始编译安装OpenSSH $OPENSSH_VERSION..."
    
    cd /tmp
    
    # 清理可能存在的旧文件
    rm -rf openssh-* 2>/dev/null || true
    
    # 下载OpenSSH源码
    log_info "下载OpenSSH源码包..."
    wget -O openssh-${OPENSSH_VERSION}.tar.gz \
        "https://mirrors.cloud.tencent.com/OpenBSD/OpenSSH/portable/openssh-${OPENSSH_VERSION}.tar.gz"
    
    # 验证下载是否成功
    if [ ! -f "openssh-${OPENSSH_VERSION}.tar.gz" ]; then
        log_error "OpenSSH源码包下载失败"
        exit 1
    fi
    
    # 解压并验证
    log_info "解压OpenSSH源码包..."
    tar -xzf openssh-${OPENSSH_VERSION}.tar.gz
    
    # 查找实际的目录名
    OPENSSH_DIR=$(find /tmp -maxdepth 1 -type d -name "openssh-*" | head -1)
    if [ -z "$OPENSSH_DIR" ] || [ ! -d "$OPENSSH_DIR" ]; then
        log_error "OpenSSH源码解压失败或目录不存在"
        ls -la /tmp/openssh* || true
        exit 1
    fi
    
    log_info "进入目录: $OPENSSH_DIR"
    cd "$OPENSSH_DIR"
    
    # 停止SSH服务
    log_info "停止现有SSH服务..."
    systemctl stop ssh 2>/dev/null || systemctl stop sshd 2>/dev/null || true
    
    # 配置编译选项
    log_info "配置编译选项..."
    export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH"
    export LD_LIBRARY_PATH="/usr/local/ssl/lib:/usr/local/ssl/lib64:$LD_LIBRARY_PATH"
    export CPPFLAGS="-I/usr/local/ssl/include"
    export LDFLAGS="-L/usr/local/ssl/lib -L/usr/local/ssl/lib64"
    
    ./configure --prefix=/usr \
                --sysconfdir=/etc/ssh \
                --with-ssl-dir=/usr/local/ssl \
                --with-pam \
                --with-zlib \
                --with-tcp-wrappers \
                --with-audit=linux \
                --with-selinux \
                --with-privsep-path=/var/lib/sshd \
                --with-privsep-user=sshd
    
    # 编译
    log_info "开始编译OpenSSH..."
    make -j$(nproc)
    
    # 备份现有SSH配置
    if [ -f /etc/ssh/sshd_config ]; then
        cp /etc/ssh/sshd_config /tmp/sshd_config.backup
        log_info "已备份现有SSH配置"
    fi
    
    # 安装
    log_info "安装OpenSSH..."
    make install
    
    # 恢复配置文件（如果存在备份）
    if [ -f /tmp/sshd_config.backup ]; then
        cp /tmp/sshd_config.backup /etc/ssh/sshd_config
        log_info "已恢复SSH配置文件"
    fi
    
    log_info "OpenSSH安装完成"
    LD_LIBRARY_PATH="/usr/local/ssl/lib:/usr/local/ssl/lib64:$LD_LIBRARY_PATH" /usr/sbin/sshd -V || true
}

# 配置SSH服务
configure_ssh() {
    log_info "配置SSH服务..."
    
    # 创建sshd用户（如果不存在）
    if ! id -u sshd > /dev/null 2>&1; then
        useradd -r -d /var/lib/sshd -s /bin/false -c "SSH daemon" sshd
    fi
    
    # 创建必要目录
    mkdir -p /var/lib/sshd
    chmod 755 /var/lib/sshd
    chown root:root /var/lib/sshd
    
    # 生成主机密钥（如果不存在）
    if [ ! -f /etc/ssh/ssh_host_rsa_key ]; then
        ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N ""
    fi
    if [ ! -f /etc/ssh/ssh_host_ecdsa_key ]; then
        ssh-keygen -t ecdsa -b 521 -f /etc/ssh/ssh_host_ecdsa_key -N ""
    fi
    if [ ! -f /etc/ssh/ssh_host_ed25519_key ]; then
        ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""
    fi
    
    # 配置sshd_config
    cat > /etc/ssh/sshd_config << EOF
# SSH配置文件 - 由脚本自动生成
Port 34022
Protocol 2

# 认证设置
PermitRootLogin yes
PubkeyAuthentication yes
PasswordAuthentication yes
PermitEmptyPasswords no

# 安全设置
MaxAuthTries 6
MaxSessions 10
ClientAliveInterval 60
ClientAliveCountMax 3

# 加密设置
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com,hmac-sha2-256,hmac-sha2-512
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521

# 日志设置
SyslogFacility AUTH
LogLevel INFO

# 其他设置
X11Forwarding no
PrintMotd no
UsePAM yes
AcceptEnv LANG LC_*
Subsystem sftp /usr/lib/openssh/sftp-server

# 主机密钥
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
EOF
    
    # 设置配置文件权限
    chmod 644 /etc/ssh/sshd_config
    
    log_info "SSH配置完成，端口已设置为34022，已启用root登录"
}

# 创建systemd服务文件
create_systemd_service() {
    log_info "配置SSH systemd服务..."
    
    # 停止现有服务
    systemctl stop ssh 2>/dev/null || true
    systemctl stop sshd 2>/dev/null || true
    
    # 禁用现有服务
    systemctl disable ssh 2>/dev/null || true  
    systemctl disable sshd 2>/dev/null || true
    
    # 删除可能存在的符号链接
    rm -f /etc/systemd/system/sshd.service 2>/dev/null || true
    rm -f /etc/systemd/system/ssh.service 2>/dev/null || true
    
    # 创建新的SSH服务文件
    cat > /etc/systemd/system/ssh.service << EOF
[Unit]
Description=OpenBSD Secure Shell server
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run

[Service]
Environment="LD_LIBRARY_PATH=/usr/local/ssl/lib:/usr/local/ssl/lib64"
EnvironmentFile=-/etc/default/ssh
ExecStartPre=/usr/sbin/sshd -t
ExecStart=/usr/sbin/sshd -D \$SSHD_OPTS
ExecReload=/bin/kill -HUP \$MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755

[Install]
WantedBy=multi-user.target
EOF
    
    # 创建sshd.service的符号链接，指向ssh.service
    ln -sf /etc/systemd/system/ssh.service /etc/systemd/system/sshd.service
    
    # 重新加载systemd配置
    systemctl daemon-reload
    
    # 启用并启动SSH服务
    systemctl enable ssh
    
    # 测试配置文件
    log_info "测试SSH配置文件..."
    if LD_LIBRARY_PATH="/usr/local/ssl/lib:/usr/local/ssl/lib64" /usr/sbin/sshd -t; then
        log_info "SSH配置文件测试通过"
        systemctl start ssh
        log_info "SSH服务已启动"
    else
        log_error "SSH配置文件测试失败"
        exit 1
    fi
    
    # 检查服务状态
    if systemctl is-active --quiet ssh; then
        log_info "SSH服务运行正常"
    else
        log_warn "SSH服务可能未正常启动，请检查日志"
        systemctl status ssh --no-pager || true
    fi
}

# 配置防火墙
configure_firewall() {
    log_info "配置防火墙规则..."
    
    # 检查防火墙状态
    if command -v ufw >/dev/null 2>&1; then
        # 使用ufw
        ufw allow 34022/tcp
        log_info "已使用ufw开放SSH端口34022"
    elif command -v iptables >/dev/null 2>&1; then
        # 使用iptables
        iptables -I INPUT -p tcp --dport 34022 -j ACCEPT
        # 尝试保存iptables规则
        if command -v iptables-save > /dev/null 2>&1; then
            iptables-save > /etc/iptables/rules.v4 2>/dev/null || true
        fi
        log_info "已使用iptables开放SSH端口34022"
    else
        log_warn "未检测到防火墙工具，请手动开放端口34022"
    fi
}

# 清理临时文件
cleanup() {
    log_info "清理临时文件..."
    rm -rf /tmp/openssl-* /tmp/openssh-* 2>/dev/null || true
}

# 显示完成信息
show_completion_info() {
    log_info "======================="
    log_info "系统更新完成！"
    log_info "======================="
    echo
    log_info "更新内容："
    echo "  - APT镜像源已更新为中科大镜像"
    echo "  - OpenSSL版本: $(openssl version 2>/dev/null || echo '安装失败')"
    echo "  - OpenSSH版本: $(/usr/sbin/sshd -V 2>&1 | head -1 || echo '版本获取失败')"
    echo "  - SSH端口已更改为: 34022"
    echo "  - Root登录已启用"
    echo
    log_info "重要提示："
    echo "  1. 请使用新端口34022连接SSH"
    echo "  2. 旧的SSH连接可能会断开"
    echo "  3. 配置文件备份在: $BACKUP_DIR"
    echo "  4. 建议重启系统以确保所有更改生效"
    echo
    log_warn "连接命令示例: ssh root@your_server_ip -p 34022"
}

# 主函数
main() {
    log_info "开始执行Debian 11 SSH/SSL更新脚本..."
    
    check_root
    backup_configs
    update_apt_sources
    install_dependencies
    get_latest_versions
    install_openssl
    install_openssh
    configure_ssh
    create_systemd_service
    configure_firewall
    cleanup
    show_completion_info
    
    log_info "脚本执行完成！"
}

# 执行主函数
main "$@"